package com.warom.sdg.config;

import com.warom.sdg.model.PlcDataEntity;
import java.util.ArrayList;
import java.util.List;

/**
 * 测点信息类
 * 表示系统中各类设备的测量点配置信息
 */
public class MeasurementPoint {
    private final String name; // 中文名称
    private final String englishName; // 英文名称
    private String address; // Modbus读取地址
    private String writeAddress; // Modbus写入地址，用于控制设备
    private String address2; // 第二个Modbus读取地址
    private String writeAddress2; // 第二个Modbus写入地址
    private final String unit; // 单位
    private final String description; // 描述信息
    private final double minValue; // 最小值
    private final double maxValue; // 最大值
    private final double warningValue; // 警告阈值
    private final double dangerValue; // 危险阈值
    private final float scaleFactor; // 缩放因子，用于从原始值计算实际值
    private final PointType pointType; // 测点类型：数值型或状态型
    private final DeviceSubType deviceSubType; // 设备子类型
    private double value; // 实时值，使用非final以允许更新

    private double value2;
     private boolean alarmState = false; // 报警状态，默认为false
    // 属性测点列表，存储与主测点关联的所有属性测点
    private List<MeasurementPoint> attributeList = new ArrayList<>();
    
    // 关联的主测点（如果当前测点是属性测点）
    private MeasurementPoint mainPoint;

    // 新增字段：更新频率(毫秒)和上次更新时间
    private long updateFrequency = 5000; // 默认5秒更新一次
    private long lastUpdateTime = 0; // 默认为0，表示从未更新过

    /**
     * 测点类型枚举
     */
    public enum PointType {
        VALUE,           // 数值型测点，需要存储历史数据
        STATUS,          // 状态型测点，仅表示开关状态，不需要存储历史数据
        ATTRIBUTE,       // 属性型测点，用于表示设备属性，不用于页面展示
        RUN_STATUS,      // 运行状态属性测点
        FAULT_ALARM      // 故障报警属性测点
    }

    /**
     * 设备子类型枚举
     */
    public enum DeviceSubType {
        UNKNOWN, // 未知类型
        AXIAL_FAN, // 轴流风机
        CIRCULATION_FAN, // 环流风机
        BUTTERFLY_VALVE, // 电动蝶阀
        FUMIGATION_FAN, // 熏蒸风机
        NATURAL_WINDOW, // 自然窗
        AXIAL_WINDOW, // 轴流通风窗
        CIRCULATION_WINDOW, // 环流通风窗
        TEMPERATURE_SENSOR, // 温度传感器
        HUMIDITY_SENSOR, // 湿度传感器
        GAS_SENSOR // 气体传感器
    }

    public MeasurementPoint(String name, String englishName, String address, String unit) {
        this(name, englishName, address, "", unit, "", 0, 100, 0, 0, 1.0f, PointType.VALUE,
                DeviceSubType.UNKNOWN, 0.0);
    }

    public MeasurementPoint(String name, String englishName, String address, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue) {
        this(name, englishName, address, "", unit, description, minValue, maxValue,
                warningValue, dangerValue, 1.0f, PointType.VALUE, DeviceSubType.UNKNOWN, 0.0);
    }

    public MeasurementPoint(String name, String englishName, String address, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue, float scaleFactor) {
        this(name, englishName, address, "", unit, description, minValue, maxValue,
                warningValue, dangerValue, scaleFactor, PointType.VALUE, DeviceSubType.UNKNOWN,
                0.0);
    }

    public MeasurementPoint(String name, String englishName, String address, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue, float scaleFactor, double value) {
        this(name, englishName, address, "", unit, description, minValue, maxValue,
                warningValue, dangerValue, scaleFactor, PointType.VALUE, DeviceSubType.UNKNOWN,
                value);
    }

    public MeasurementPoint(String name, String englishName, String address, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue, float scaleFactor, PointType pointType) {
        this(name, englishName, address, "", unit, description, minValue, maxValue,
                warningValue, dangerValue, scaleFactor, pointType, DeviceSubType.UNKNOWN, 0.0);
    }

    public MeasurementPoint(String name, String englishName, String address, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue, float scaleFactor, PointType pointType,
            double value) {
        this(name, englishName, address, "", unit, description, minValue, maxValue,
                warningValue, dangerValue, scaleFactor, pointType, DeviceSubType.UNKNOWN,
                value);
    }

    public MeasurementPoint(String name, String englishName, String address, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue, float scaleFactor, PointType pointType,
            DeviceSubType deviceSubType, double value) {
        this(name, englishName, address, "", unit, description, minValue, maxValue,
                warningValue, dangerValue, scaleFactor, pointType, deviceSubType, value);
    }

    public MeasurementPoint(String name, String englishName, String address, String writeAddress, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue, float scaleFactor, PointType pointType,
            DeviceSubType deviceSubType, double value) {
        this(name, englishName, address, writeAddress, "", "", unit, description, minValue, maxValue,
                warningValue, dangerValue, scaleFactor, pointType, deviceSubType, value);
    }

    public MeasurementPoint(String name, String englishName, String address, String writeAddress, 
            String address2, String writeAddress2, String unit,
            String description, double minValue, double maxValue,
            double warningValue, double dangerValue, float scaleFactor, PointType pointType,
            DeviceSubType deviceSubType, double value) {
        this.name = name;
        this.englishName = englishName;
        this.address = address;
        this.writeAddress = writeAddress;
        this.address2 = address2;
        this.writeAddress2 = writeAddress2;
        this.unit = unit;
        this.description = description;
        this.minValue = minValue;
        this.maxValue = maxValue;
        this.warningValue = warningValue;
        this.dangerValue = dangerValue;
        this.scaleFactor = scaleFactor;
        this.pointType = pointType;
        this.deviceSubType = deviceSubType;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public String getEnglishName() {
        return englishName;
    }

    public String getAddress() {
        return address;
    }

    public String getWriteAddress() {
        return writeAddress;
    }

    public String getAddress2() {
        return address2;
    }

    public String getWriteAddress2() {
        return writeAddress2;
    }

    public String getUnit() {
        return unit;
    }

    public String getDescription() {
        return description;
    }

    public double getMinValue() {
        return minValue;
    }

    public double getMaxValue() {
        return maxValue;
    }

    public double getWarningValue() {
        return warningValue;
    }

    public double getDangerValue() {
        return dangerValue;
    }

    public float getScaleFactor() {
        return scaleFactor;
    }

    public PointType getPointType() {
        return pointType;
    }

    public DeviceSubType getDeviceSubType() {
        return deviceSubType;
    }

    /**
     * 检查测点是否为状态型
     * 
     * @return 如果测点是状态型返回true，否则返回false
     */
    public boolean isStatusPoint() {
        return pointType == PointType.STATUS;
    }

    /**
     * 检查测点是否为数值型
     * 
     * @return 如果测点是数值型返回true，否则返回false
     */
    public boolean isValuePoint() {
        return pointType == PointType.VALUE;
    }

    /**
     * 检查测点是否为轴流风机
     * 
     * @return 如果测点是轴流风机返回true，否则返回false
     */
    public boolean isAxialFan() {
        return deviceSubType == DeviceSubType.AXIAL_FAN;
    }

    /**
     * 检查测点是否为环流风机
     * 
     * @return 如果测点是环流风机返回true，否则返回false
     */
    public boolean isCirculationFan() {
        return deviceSubType == DeviceSubType.CIRCULATION_FAN;
    }

    /**
     * 检查测点是否为属性型
     * 
     * @return 如果测点是属性型返回true，否则返回false
     */
    public boolean isAttributePoint() {
        return pointType == PointType.ATTRIBUTE || 
               pointType == PointType.RUN_STATUS || 
               pointType == PointType.FAULT_ALARM;
    }

    /**
     * 获取测点实时值
     * 
     * @return 实时值
     */
    public double getValue() {
        return value;
    }

    /**
     * 设置测点实时值
     * 
     * @param value 实时值
     */
    public void setValue(double value) {
        // 格式化为保留2位小数
        this.value = Math.round(value * 100) / 100.0;
        
        // 如果是属性测点，处理值变化
        if (isAttributePoint() && mainPoint != null) {
            processAttributeChange();
        }
    }

    /**
     * 获取报警状态
     * 
     * @return 报警状态
     */
    public boolean isAlarmState() {
        return alarmState;
    }

    /**
     * 设置报警状态
     * 
     * @param alarmState 报警状态
     */
    public void setAlarmState(boolean alarmState) {
        this.alarmState = alarmState;
    }

    /**
     * 将测点信息转换为PLC数据实体
     * 
     * @param deviceId 设备ID
     * @return PLC数据实体
     */
    public PlcDataEntity toPlcDataEntity(int deviceId) {
        PlcDataEntity entity = new PlcDataEntity();
        entity.setDeviceId(deviceId);
        entity.setName(name);
        entity.setEnglishName(englishName);
        entity.setAddress(address);
        entity.setValue(String.valueOf(value));
        entity.setUnit(unit);
//        entity.setDescription(description);
//        entity.setMinValue(minValue);
//        entity.setMaxValue(maxValue);
//        entity.setWarningValue(warningValue);
//        entity.setDangerValue(dangerValue);
        entity.setAlarmState(alarmState);
        return entity;
    }

    /**
     * 检查测点是否有写入地址
     * 
     * @return 如果测点有写入地址返回true，否则返回false
     */
    public boolean hasWriteAddress() {
        return writeAddress != null && !writeAddress.isEmpty();
    }

    /**
     * 检查测点是否为自然通风窗
     * 
     * @return 如果测点是自然通风窗返回true，否则返回false
     */
    public boolean isNaturalWindow() {
        return deviceSubType == DeviceSubType.NATURAL_WINDOW;
    }

    /**
     * 设置测点读取地址
     * 
     * @param address 新的Modbus读取地址
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /**
     * 设置测点写入地址
     * 
     * @param writeAddress 新的Modbus写入地址
     */
    public void setWriteAddress(String writeAddress) {
        this.writeAddress = writeAddress;
    }

    /**
     * 设置第二个Modbus读取地址
     * 
     * @param address2 新的第二个Modbus读取地址
     */
    public void setAddress2(String address2) {
        this.address2 = address2;
    }

    public double getValue2() {
        return value2;
    }

    public void setValue2(double value2) {
        this.value2 = value2;
    }

    public List<MeasurementPoint> getAttributeList() {
        return attributeList;
    }

    public void setAttributeList(List<MeasurementPoint> attributeList) {
        this.attributeList = attributeList;
    }

    /**
     * 设置第二个Modbus写入地址
     * 
     * @param writeAddress2 新的第二个Modbus写入地址
     */
    public void setWriteAddress2(String writeAddress2) {
        this.writeAddress2 = writeAddress2;
    }

    /**
     * 添加属性测点
     * 
     * @param attributePoint 属性测点
     */
    public void addAttributePoint(MeasurementPoint attributePoint) {
        if (attributePoint != null && attributePoint.isAttributePoint()) {
            attributeList.add(attributePoint);
            attributePoint.setMainPoint(this);
        }
    }
    
    /**
     * 获取属性测点列表
     * 
     * @return 属性测点列表
     */
    public List<MeasurementPoint> getAttributePoints() {
        return attributeList;
    }
    
    /**
     * 设置主测点引用
     * 
     * @param mainPoint 主测点
     */
    public void setMainPoint(MeasurementPoint mainPoint) {
        this.mainPoint = mainPoint;
    }
    
    /**
     * 获取主测点
     * 
     * @return 主测点，如果当前测点不是属性测点则返回null
     */
    public MeasurementPoint getMainPoint() {
        return mainPoint;
    }
    
    /**
     * 处理属性测点值变化
     */
    public void processAttributeChange() {
        if (mainPoint == null) {
            return;
        }
        
        if (pointType == PointType.RUN_STATUS) {
            // 运行状态
            mainPoint.setValue(this.getValue());
        } else if (pointType == PointType.FAULT_ALARM) {
            // 故障报警
            mainPoint.setAlarmState(this.getValue() > 0);
        }
    }

    /**
     * 创建自然通风窗测点的便捷构造函数
     * 
     * @param name 测点名称
     * @param englishName 英文名称
     * @param address 主读取地址
     * @param writeAddress 主写入地址
     * @param address2 第二读取地址
     * @param writeAddress2 第二写入地址
     * @param description 描述
     * @return 自然通风窗测点对象
     * @deprecated 使用 {@link #createWindow(String, String, String, String, String, String, String, DeviceSubType)} 替代
     */
    @Deprecated
    public static MeasurementPoint createNaturalWindow(String name, String englishName, 
            String address, String writeAddress, String address2, String writeAddress2, 
            String description) {
        return createWindow(name, englishName, address, writeAddress, address2, writeAddress2,
                description, DeviceSubType.NATURAL_WINDOW);
    }
    
    /**
     * 创建通风窗测点的通用方法
     * 
     * @param name 测点名称
     * @param englishName 英文名称
     * @param address 主读取地址
     * @param writeAddress 主写入地址
     * @param address2 第二读取地址
     * @param writeAddress2 第二写入地址
     * @param description 描述
     * @param deviceSubType 设备子类型
     * @return 通风窗测点对象
     */
    public static MeasurementPoint createWindow(String name, String englishName, 
            String address, String writeAddress, String address2, String writeAddress2, 
            String description, DeviceSubType deviceSubType) {
        return new MeasurementPoint(
            name, englishName, address, writeAddress, address2, writeAddress2, "",
            description, 0, 1, 0, 0, 1.0f, PointType.STATUS, deviceSubType, 0.0
        );
    }

    /**
     * 获取更新频率(毫秒)
     * 
     * @return 更新频率
     */
    public long getUpdateFrequency() {
        return updateFrequency;
    }

    /**
     * 设置更新频率(毫秒)
     * 
     * @param updateFrequency 更新频率
     */
    public void setUpdateFrequency(long updateFrequency) {
        this.updateFrequency = updateFrequency;
    }

    /**
     * 获取上次更新时间(毫秒)
     * 
     * @return 上次更新时间
     */
    public long getLastUpdateTime() {
        return lastUpdateTime;
    }

    /**
     * 设置上次更新时间(毫秒)
     * 
     * @param lastUpdateTime 上次更新时间
     */
    public void setLastUpdateTime(long lastUpdateTime) {
        this.lastUpdateTime = lastUpdateTime;
    }
    
    /**
     * 检查是否需要更新数据
     * 
     * @return 如果需要更新返回true，否则返回false
     */
    public boolean shouldUpdate() {
        long currentTime = System.currentTimeMillis();
        // 如果从未更新过，或者已经超过更新频率，则需要更新
        return lastUpdateTime == 0 || (currentTime - lastUpdateTime) >= updateFrequency;
    }
    
    /**
     * 更新最后更新时间为当前时间
     */
    public void updateLastUpdateTime() {
        this.lastUpdateTime = System.currentTimeMillis();
    }
} 